package com.ablecloud.demo;

import static org.junit.Assert.fail;

import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ablecloud.common.ACContext;
import com.ablecloud.common.ACDeviceMsg;
import com.ablecloud.common.ACDeviceReportInfo;
import com.ablecloud.common.ACFilter;
import com.ablecloud.common.ACMsg;
import com.ablecloud.common.ACObject;
import com.ablecloud.common.ACServiceException;
import com.ablecloud.common.Errors;
import com.ablecloud.service.ACDStore;
import com.ablecloud.service.ACService;

public class DemoService extends ACService {
    private static final Logger logger = LoggerFactory.getLogger(DemoService.class);

    /**
     * 重载init函数。
     *
     * @throws Exception
     */
    public void init() throws Exception {
    }

    /**
     * 处理来自APP或其它service发来消息的入口函数
     *
     * @param req  请求消息
     * @param resp 响应消息
     * @throws Exception
     */
    public void handleMsg(ACMsg req, ACMsg resp) throws Exception {
        String name = req.getName();
        ACContext context = req.getContext();
        String userId = req.getName();
        String username = req.getString("username");
        
        logger.info("function name:  "+name);
        logger.info("device ID :" +req.getString("deviceId"));
        switch (name) {
            /*case "controlLight":
                handleControlLight(req, resp);
                break;*/
           	case "getDeviceList":
           		getDeviceList(req,resp,context,username);
           		break;
           	case "updateDeviceGroupId":
           		updateDeviceGroupId(req,resp,context);
           		break;
           	case "updateUserGroupId":
           		updateUserGroupId(req,resp,context,username);
           		break;
           	case "createGroup":
           		createGroup(req,resp,context);
           		break;
           	case "deleteGroup":
           		deleteGroup(req,resp,context);
           		break;
            case "test":
                logger.info(req.toString());
                resp.put("result", "userId[" + req.getContext().getUserId() + "] is testing, return ack");
                resp.setAck();
                break;
                
            case "exportHistoryd":
            	exportHistoryd(req,resp,context);	
                break;
            default:            	
                logger.warn("got an invalid request, method[" + name + "] is not implemented.");
                resp.setErr(Errors.ERR_MSG_NOT_SUPPORTED.code, Errors.ERR_MSG_NOT_SUPPORTED.error);
                break;
        }
    }
    
    /**
     * 
     * 获取设备dstore 存储的设备 
     * @param req
     * @param resp
     * @param context
     * @throws Exception 
     */
   
    private void exportHistoryd(ACMsg req, ACMsg resp, ACContext context) throws Exception {
		// TODO Auto-generated method stub
    	String subDomainName=req.getString("subDomainName");
    	long deviceId=req.getLong("deviceId");
        logger.info("DemoService 99 deviceId:"+deviceId);
        //需要添加List<ACObject> 现在只能获取一个数据
	    ACObject deviceData= ac.dstore(subDomainName).exportHistory(deviceId).execute().next();
	    logger.info("DemoService 103 deviceData:"+deviceData);
	    resp.put("deviceData", deviceData);
    	resp.setAck();
	}           
    
	/**
     * 删除组
     * <p/>
      * @throws Exception 
     *  
     *  
     */   
    private void deleteGroup(ACMsg req, ACMsg resp, ACContext context) throws Exception{
    	int groupId=req.getInt("groupId");
    	logger.info("deleteGroup","删除组"+groupId);
		List<ACObject> objects=ac.store(context, "Group").scan("parentId",groupId).execute();
		int parentId=ac.store(context, "Group").find("groupId",groupId).execute().getInt("parentId");
		for(int i=0;i<objects.size();i++){
			
			ac.store(context, "Group").modify("groupId",objects.get(i).getInt("groupId"))
			.set("parentId", parentId).execute();
		}
		ac.store(context, "Group").delete("groupId",groupId).execute();
		logger.info("deleteGroup","删除成功!");
		resp.setAck();
	}
    
    /**
     * 创建组
     * <p/>
      * @throws Exception 
     *  
     *  
     */   
    private void createGroup(ACMsg req, ACMsg resp, ACContext context) throws Exception{
    	int groupId=req.getInt("groupId");
    	logger.info("createGroup","创建组");
		ac.store(context, "Group").create("parentId",groupId).execute();;
		resp.put("result", "success");
		logger.info("createGroup","创建成功!");
		resp.setAck();
	}

    /**
     * 更改用户组
     * <p/>
      * @throws Exception 
     *  
     *  
     */   
    private void updateUserGroupId(ACMsg req, ACMsg resp, ACContext context,String username) throws Exception{
    	int groupId=req.getInt("groupId");
    	logger.info("updateUserGroupId","用户"+username);
		ac.store(context, "User").modify("userName",username).set("groupId", groupId).execute();
		resp.put("result", "success");
		resp.put("groupID", groupId);
		logger.info("updateUserGroupId","更改成功!");
		resp.setAck();
	}
    
    /**
     * 更改设备组
     * <p/>
      * @throws Exception 
     *  
     *  
     */   
    private void updateDeviceGroupId(ACMsg req, ACMsg resp, ACContext context) throws Exception{
    	int groupId=req.getInt("groupId");
    	int deviceId=req.getInt("deviceId");
    	logger.info("updateDeviceGroupId","组号"+groupId+" 设备号"+deviceId);
		ac.store(context, "Device").modify("deviceId",deviceId).set("groupId", groupId).execute();
		resp.put("result", "success");
		resp.put("groupID", groupId);
		logger.info("updateDeviceGroupId","更改成功!");
		resp.setAck();
	}

	/**
     * 内部获取子权限
     * <p/>
      * @throws Exception 
     *  
     *  
     */   
    /*private int getChildID(String username,ACContext context)throws Exception {
    	logger.info("getDeviceList",username);
    	ACObject permission=ac.store("Permission",context)
    			.find("userName",username)
    			.execute();
    	logger.info("getDeviceList",username);
    	return permission.getInt("userPermission");  			
	}*/
    

	
    /**
     * 处理来自APP端的查询设备列表和用户列表消息
     * <p/>
      * @throws Exception 
      * @param context ACContext
     *  @param username 用户账号（手机号）
     *  
     */   
    private void getDeviceList(ACMsg req, ACMsg resp,ACContext context,String username)throws Exception {
    	logger.info("getDeviceList",req.getString("username"));
    	//ACFilter filter = ac.filter().whereGreaterThanOrEqualTo("ParentId",parentID);
    	int groupId=ac.store(context, "User").find("userName",username).execute().getInt("groupId");
    	//存储遍历组间关系树得到的组id
    	ArrayList<Integer> groupIds = new ArrayList<>();
    	//用来判定是否有满足父id的组
    	ArrayList<Integer> flagList = new ArrayList<>();
    	flagList.add(groupId);
    	//每次循环寻找所有满足父id条件的组
    	while(flagList.size()!=0){
    		//用来暂存前一次的组id
    		ArrayList<Integer> tempList=new ArrayList<>();
    		
    		for(int i = 0;i<flagList.size();i++){
    			groupIds.add(flagList.get(i));
    			tempList.add(flagList.get(i));
    		}
    		
    		flagList.clear();
    		
    		for(int i = 0;i<tempList.size();i++){
    			List<ACObject> groups=ac.store(context, "Group")
    					.scan("parentId",tempList.get(i)).execute();
    			for(int j = 0;j<groups.size();j++)
    				flagList.add(groups.get(j).getInt("groupId"));
    		}
    		
    	}
    	
    	logger.info("查到的组号"+groupIds.toString());
    	
    	ArrayList<ACObject> deviceList=new ArrayList<>();
    	ArrayList<ACObject> userList=new ArrayList<>();
    	//查询groupIds中所有组号下的设备和用户
    	for(int i = 0;i<groupIds.size();i++){
    		List<ACObject> tempDeviceList=ac.store(context, "Device").scan("groupId",groupIds.get(i))
    				.execute();
    		List<ACObject> tempUserList=ac.store(context, "User").scan("groupId",groupIds.get(i))
    				.execute();
    		for(int j = 0;j<tempDeviceList.size();j++)
    			deviceList.add(tempDeviceList.get(j));
    		for(int j = 0;j<tempUserList.size();j++)
    			userList.add(tempUserList.get(j));
    	}    	
    	logger.info("设备列表:"+deviceList.toString()+"  用户列表:"+userList.toString());
    	resp.put("deviceList", deviceList);
    	resp.put("userList", userList);
        resp.put("groupIds", groupIds);
        resp.put("result", "success");
    	resp.setAck();
	}
    
	/**
     * 处理来自设备上报消息的入口函数
     *
     * @param reportInfo 设备的属性
     * @param req        设备上报消息
     * @throws Exception
     */
    public void handleDeviceMsg(ACDeviceReportInfo reportInfo, ACDeviceMsg req) throws Exception {
        int msgCode = req.getCode();
        
        logger.info("DemoService,"+Arrays.toString(req.getContent()));
        logger.info("DemoService,246,msgCode:"+msgCode);
        switch (msgCode) {        	
            case LightMsg.REPORT_CODE:        
                handleLightReport(reportInfo, req.getContent());                                   
                break; 
            case MachineMsg.REPORT_CODE:
            	handleMachineReport(reportInfo,req.getObject());  
            	System.out.println(Arrays.toString(req.getContent()));    	
            	break;
            case MachineMsg.TABLE_CODE:
            	handleMachineReportInTable(reportInfo,req.getObject());
            	break;
            default:
                logger.warn("got an unknown report, opcode[" + msgCode + "]");
        }
    }

    
    /**
     * 处理匿名请求。某些特殊请求，如用户注册，没有有效用户的信息，可以考虑使用匿名请求的方式执行。
     * 
     * @param req  请求消息体
     * @param resp 响应消息体
     * @throws Exception
     */
    public void handleAnonymousMsg(ACMsg req, ACMsg resp) throws Exception {
        String name = req.getName();
        switch (name) {
            case "register":  // 用户注册。
                handleRegister(req, resp);
                break;
            default:
                logger.warn("got an invalid request, method[" + name + "] is not implemented.");
                resp.setErr(Errors.ERR_MSG_NOT_SUPPORTED.code, Errors.ERR_MSG_NOT_SUPPORTED.error);
                break;
        }
    }
    
    
    /**
     * 处理来自APP端的智能灯控制命令，再将命令发往具体的设备
     * <p/>
     * 实际上，厂商在实现后端服务的时候，通常情况下自定义服务不用处理APP端发来的设备控制请求也
     * 能实现远程控制。因为ablecloud在云端提供了设备管理服务，APP通过APP端的sendToDevice
     * 接口可以将控制命令远程发往ablecloud的设备管理服务，设备管理服务再将控制命令发给设备。
     * <p/>
     * 本示例在开发者自定义的这个服务中实现对灯的控制，一方面是为了展示后端服务的灵活性，可以作
     * 各种事情，包括对设备的控制，比如后端服务在多设备联动的时候，可能会主动往设备发控制命令。
     *
     * @param req  请求消息
     * @param resp 响应消息
     * @throws Exception
     */         
    private void handleControlLight(ACMsg req, ACMsg resp) throws Exception {
        long userId = req.getContext().getUserId();
        long lightId = req.getLong("deviceId");
        String action = req.get("action");
        int deviceAction;
        if (action.equalsIgnoreCase("on")) {
            deviceAction = 1;
        } else
            deviceAction = 0;
        ACDeviceMsg deviceReqMsg = new ACDeviceMsg(LightMsg.CODE, new ACObject()
        .put(LightMsg.KEY_SWITCH, deviceAction).put(LightMsg.KEY_SOURCE, 0));
        ACDeviceMsg deviceRespMsg;
        try {
            // 获取子域
            // (1) 此处通过已过时的方法 ACConfig.getSubDomain 来指定设备所属的子域名。这是旧的子域级别UDS中的使用方法。
            // 新版的云应用引擎不支持从配置项（ACConfig）中获取子域名（返回值为空字符串）。此时应通过其它方法指定子域，如从请求的上下文中获取（如果存在）、从请求参数中获取等。
            // String subDomainName = this.getAc().getACConfig().getSubDomain();
            // (2) 从请求上下文中获取子域
            String subDomainName = req.getContext().getSubDomainName();
            // (3) 从请求参数中获取子域
            // String subDomainName = req.get("subDomain");
            
            // 通过ac框架的sendToDevice接口，向灯发送控制命令
            deviceRespMsg = ac.bindMgr(req.getContext()).sendToDevice(subDomainName, lightId, deviceReqMsg, userId);
            // 获取控制开关结果
            byte[] payload = deviceRespMsg.getContent();
            if (payload.length > 0 && payload[0] == 1)
                resp.put("result", "success");
            else
                resp.put("result", "fail");
            resp.setAck();
            logger.info("handle control light ok, action[" + action + "].");
        } catch (ACServiceException e) {
            resp.setErr(e.getErrorCode(), e.getErrorMsg());
            logger.warn("send to device[" + lightId + "] error:", e);
        }
    }


    /**
     * 处理智能灯汇报的消息，在该函数中，服务还将收到的汇报数据写入ablecloud提供的云端存储中。
     *
     * @param reportInfo 汇报数据的设备的信息。
     * @param payload  汇报的具体消息内容。
     * @throws Exception
     */
    private void handleLightReport(ACDeviceReportInfo reportInfo, byte[] payload) throws Exception {
    	
    	try {
    		
    		logger.info("348 DemoService payload:"+payload[0]);
    		LightMsg lightMsg = new LightMsg(payload);
            // 通过ac框架，将智能灯汇报的数据存入云端存储
            logger.info("上报数据:"+lightMsg.getLedOnOff()/*+lightMsg.getSource()*/);
            ac.dstore(reportInfo.getContext().getSubDomainName())
                    .create(reportInfo.getDeviceId(), System.currentTimeMillis())
                    .put(LightMsg.KEY_SWITCH, lightMsg.getLedOnOff())
                    //.put(LightMsg.KEY_SOURCE, lightMsg.getSource())
                    .execute(true); //true:为存储属性并发布推送 false:只存储属性数据            		                    
        } catch (ACServiceException e) {
            logger.warn("handle light report error:", e);
        }
    }

    /**
     * 处理APP端发来的用户注册请求。用户注册的请求使用匿名访问的方式。
     *
     * @param req  请求消息
     * @param resp 响应消息
     * @throws Exception
     */
    private void handleRegister(ACMsg req, ACMsg resp) throws Exception {
        // 实现用户注册的逻辑，并设置响应的结果。
        resp.setAck();    // 注册成功返回OK。
        // 注册失败是返回错误消息。
        // resp.setErr(errCode, errMessage);
    }


/*处理机器信息，并将信息存储在云端
 
*/
private void handleMachineReport(ACDeviceReportInfo reportInfo, ACObject payload) throws Exception {	
	try {			
     MachineMsg machineMsg = new MachineMsg(payload.getInt(MachineMsg.KEY_SOURCE),payload.getInt(MachineMsg.KEY_STATUS),
    		 				payload.getInt(MachineMsg.KEY_CADENCE),payload.getInt(MachineMsg.KEY_LOAD));     
     logger.info("handleMachineReport,225: machineMsg.load:"+String.valueOf(machineMsg.getLoad()));
     
       // 通过ac框架，将汇报的数据存入云端存储
        ac.dstore(reportInfo.getContext().getSubDomainName())
                .create(reportInfo.getDeviceId(), System.currentTimeMillis())
                .put(MachineMsg.KEY_SOURCE,machineMsg.getSource())
                .put(MachineMsg.KEY_STATUS,machineMsg.getStatus())
                .put(MachineMsg.KEY_CADENCE,machineMsg.getCadence())
                .put(MachineMsg.KEY_LOAD, machineMsg.getLoad())             
                .execute(true); //true:为存储属性并发布推送       false:只存储属性数据   		
    } catch (ACServiceException e) {
        logger.warn("handle light report error:", e);
    }
}


private void handleMachineReportInTable(ACDeviceReportInfo reportInfo, ACObject payload)throws Exception {	
	
	try {			
		ACContext ctx=reportInfo.getContext();
		//payload为消息的消息体，可以直接使用getxx(参数名)来得到相应的值，
	     MachineMsg machineMsg = new MachineMsg(payload.getInt(MachineMsg.KEY_SOURCE),payload.getInt(MachineMsg.KEY_STATUS),
	    		 				payload.getInt(MachineMsg.KEY_CADENCE),payload.getInt(MachineMsg.KEY_LOAD));
	     
	     ac.store("a1", ctx).create("device_id",reportInfo.getDeviceId(),"timestamp", System.currentTimeMillis())
	     .put(MachineMsg.KEY_SOURCE,machineMsg.getSource())
         .put(MachineMsg.KEY_STATUS,machineMsg.getStatus())
         .put(MachineMsg.KEY_CADENCE,machineMsg.getCadence())
         .put(MachineMsg.KEY_LOAD, machineMsg.getLoad())        
	     .execute();	     
	}catch (ACServiceException e) {
        logger.warn("handle light report error:", e);
    }
	
	
}

}





